﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace CancelToken
{
    class Program
    {
        private static int iteration = 0;
        private static double testResult = 0;
        static void Main(string[] args)
        {
            TestAgain();
            Console.ReadKey();
        }

        public async static Task Test()
        {
            CancellationTokenSource cts1 = new CancellationTokenSource();
            CancellationTokenSource cts2 = new CancellationTokenSource();
            var cts3 = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token);

            cts1.Token.Register(() =>
            {
                Console.WriteLine("cts1 Canceling");
            });
            cts2.Token.Register(() =>
            {
                Console.WriteLine("cts2 Canceling");
            });
            //cts2.CancelAfter(1000);

            cts3.Token.Register(() =>
            {
                Console.WriteLine("root Canceling");
            });

            var res = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts1.Token);
            var result = await res.Content.ReadAsStringAsync();
            Console.WriteLine("cts1:{0}", result);

            var res2 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts2.Token);
            var result2 = await res2.Content.ReadAsStringAsync();
            Console.WriteLine("cts2:{0}", result2);
            cts2.CancelAfter(0);

            var res3 = await new HttpClient().GetAsync("http://www.weather.com.cn/data/sk/101110101.html", cts3.Token);
            var result3 = await res3.Content.ReadAsStringAsync();
            Console.WriteLine("cts3:{0}", result3);
        }

        private static void MicrosoftExample()
        {
            // Define the cancellation token.
            CancellationTokenSource source = new CancellationTokenSource();
            CancellationToken token = source.Token;

            Random rnd = new Random();
            Object lockObj = new Object();

            List<Task<int[]>> tasks = new List<Task<int[]>>();
            TaskFactory factory = new TaskFactory(token);
            for (int taskCtr = 0; taskCtr <= 10; taskCtr++)
            {
                 iteration = taskCtr + 1;
                tasks.Add(factory.StartNew(() =>
                {
                    int value;
                    int[] values = new int[10];
                    for (int ctr = 1; ctr <= 10; ctr++)
                    {
                        lock (lockObj)
                        {
                            value = rnd.Next(0, 11);
                        }
                        if (value == 0)
                        {
                            source.Cancel();
                            Console.WriteLine("Cancelling at task {0}", iteration);
                            break;
                        }
                        values[ctr - 1] = value;
                    }
                    return values;
                }, token));
            }

            Console.WriteLine("iteration:"+ iteration);
            try
            {
                Task<double> fTask = factory.ContinueWhenAll(tasks.ToArray(),
                                                             (results) =>
                                                             {
                                                                 Console.WriteLine("Calculating overall mean...");
                                                                 long sum = 0;
                                                                 int n = 0;
                                                                 foreach (var t in results)
                                                                 {
                                                                     foreach (var r in t.Result)
                                                                     {
                                                                         sum += r;
                                                                         n++;
                                                                     }
                                                                 }
                                                                 return sum / (double)n;
                                                             }, token);
                Console.WriteLine("The mean is {0}.", fTask.Result);
                testResult = fTask.Result;
            }
            catch (AggregateException ae)
            {
                foreach (Exception e in ae.InnerExceptions)
                {
                    if (e is TaskCanceledException)
                    {
                        Console.WriteLine("Unable to compute mean: {0}",
                            ((TaskCanceledException)e).Message);
                        Console.WriteLine("Result:" + testResult);
                    }
                    else
                        Console.WriteLine("Exception: " + e.GetType().Name);
                }
            }
            finally
            {
                source.Dispose();
            }
        }

        private static void TestMySelf()
        {
            CancellationTokenSource source = new CancellationTokenSource();
            CancellationToken token = source.Token;
            try
            {
                source.Cancel();
            }
            catch (AggregateException ae)
            {
                Console.WriteLine("aggregateException");
            }
        }

        private static void TestBreak()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("i:" + i);
                for (int j = 0; j < 10; j++)
                {
                    if (j == 8) break;
                }
            }
        }

        private static void TestAgain()
        {
            var cancelSource = new CancellationTokenSource();
            new Thread(() =>
            {
                try
                {
                    Work(cancelSource.Token); 
                }
                catch (OperationCanceledException)
                {
                    Console.WriteLine("Canceled!");
                }
            }).Start();

            Thread.Sleep(1000);
            cancelSource.Cancel(); // Safely cancel worker.
            Console.ReadLine();
        }

        private static void Work(CancellationToken cancelToken)
        {
            while (true)
            {
                Console.Write("345");
                cancelToken.ThrowIfCancellationRequested();
            }
        }
    }

}
